package com.tmt.im.service.interfaces.impl;

import com.alibaba.fastjson2.JSONObject;
import com.tmt.im.common.enums.ChatSessionType;
import com.tmt.im.common.pojo.BlackBillPoJo;
import com.tmt.im.common.pojo.ChatSessionMemberPoJo;
import com.tmt.im.common.pojo.ChatSessionPoJo;
import com.tmt.im.common.pojo.IMUserPoJo;
import com.tmt.im.common.vo.NewChatSessionVo;
import com.tmt.im.service.config.beans.CurrentServiceProperties;
import com.tmt.im.service.controller.vo.*;
import com.tmt.im.service.helper.IgniteQueryHelper;
import com.tmt.im.service.interfaces.IChatSessionManager;
import com.tmt.im.service.interfaces.IYunXinInterface;
import com.tmt.im.service.service.ChatSessionService;
import com.tmt.springboot.common.restful.ExecuteResult;
import com.tmt.springboot.common.restful.IExecuteResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.CollectionUtils;

import java.security.Principal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 云信平台聊天管理器
 *
 * @Description TODO
 * @Author wuyi
 * @Date 2024/8/28 9:59
 * @Version 1.0
 **/
@Slf4j
public class YunXinChatSessionManager implements IChatSessionManager, ApplicationContextAware {

    private ChatSessionService sessionService;

    private IYunXinInterface iYunXinInterface;

    private CurrentServiceProperties serviceProperties;

    @Override
    public ChatSessionDetailVo createSession(Long creatorId,
                                             NewChatSessionVo newSession,
                                             StringBuilder error) {
        IMUserPoJo userPoJo = sessionService.getCurrentUser(creatorId);

        //初始拉人群中的成员必须试当前用户的好友。
        for (Long invitedId : newSession.getInvitedIds()) {
            if (!Objects.equals(creatorId, invitedId) && !sessionService.isFriend(creatorId, invitedId)) {
                IMUserPoJo friend = sessionService.getUserCache().get(invitedId);
                error.append(MessageFormat.format("用户【{0}】不是当前用户的好友", friend.getNickname()));
                return null;
            }
        }

        //先到云信平台中创建群组。
        JSONObject jsonObject = iYunXinInterface.createSession(creatorId, userPoJo.getNickname(), newSession, error);
        if (jsonObject == null) {
            return null;
        }

        //再在本地系统中创建群组。
        IExecuteResult<ChatSessionDetailVo> result = sessionService.createSession(creatorId, newSession, jsonObject);
        if (result.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(result.getMsg());
            return null;
        }
        return result.getData();
    }

    @Override
    public ChatSessionDetailVo getSessionDetail(Long operatorId, Long tid, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(tid);
        if (poJo == null) {
            error.append(MessageFormat.format("群组ID(tid={0})不存在", "" + tid));
            return null;
        }

        ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(operatorId, tid);
        if (memberPoJo == null) {
            error.append("当前用户不是目标群组的成员");
            return null;
        }

        JSONObject jsonObject = iYunXinInterface.getSessionDetail(tid, error);
        if (jsonObject == null) {
            return null;
        }

        //直接返回缓存中的数据
        IExecuteResult<ChatSessionDetailVo> detailVo = sessionService.getSessionDetail(tid, jsonObject, principal);
        if (detailVo.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(detailVo.getMsg());
            return null;
        }
        return detailVo.getData();
    }

    @Override
    public IExecuteResult<ChatSessionDetailVo> updateSession(Long operatorId, UpdateSessionRequest request, Principal principal) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组(ID={0})不存在", "" + request.getTid()), null);
        }

        if (!Objects.equals(poJo.getOwnerId(), operatorId)) {
            return ExecuteResult.failure("当前用户不是群主", null);
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        if (poJo.getInviteMode() != 1) {
            //默认设置群邀请权限为：所有人
            request.setInviteMode(1);
        }

        //先更新云平台数据。
        StringBuilder error = new StringBuilder();
        iYunXinInterface.updateSession(operatorId, type, request, error);

        //再更新本地系统中的数据。
        IExecuteResult<ChatSessionDetailVo> result = sessionService.updateSession(request, principal);
        if (result.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(result.getMsg());
            return null;
        }
        return result;
    }

    @Override
    public boolean deleteSession(Long operatorId, Long tid, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(tid);
        if (poJo == null) {
            error.append(MessageFormat.format("群组ID(tid={0})不存在", "" + tid));
            return false;
        }

        if (!Objects.equals(poJo.getOwnerId(), operatorId)) {
            error.append("当前用户不是群主");
            return false;
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        //先到云信平台中解散群组。
        if (!iYunXinInterface.deleteSession(operatorId, type, tid, error)) {
            return false;
        }

        //再删除本地系统中的群组。
        IExecuteResult<Boolean> executeResult = sessionService.deleteSession(operatorId, tid, principal);
        if (executeResult.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(executeResult.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public boolean bannedSession(Long operatorId, SessionBannedRequest request, Principal principal, StringBuilder error) {
        if (!List.of(0, 1, 3).contains(request.getMuteType())) {
            error.append("禁言类型参数(muteType)无效：只能是0、1或3");
            return false;
        }

        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("群组(ID={0})不存在", "" + request.getTid()));
            return false;
        }

        if (!poJo.getOwnerId().equals(operatorId)) {
            error.append("当前用户不是群主");
            return false;
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        //先到云信平台中转让群主。
        if (!iYunXinInterface.bannedSession(operatorId, type, request.getTid(), request.getMuteType(), error)) {
            return false;
        }

        //再更新本地系统中的群主信息。
        IExecuteResult<Boolean> executeResult = sessionService.bannedSession(operatorId, request.getTid(), request.getMuteType(), principal);
        if (executeResult.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(executeResult.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public boolean changeJoinMode(Long operatorId, SessionJoinModeRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("群组(ID={0})不存在", "" + request.getTid()));
            return false;
        }

        if (!poJo.getOwnerId().equals(operatorId)) {
            error.append("当前用户不是群主");
            return false;
        }

        //先到云信平台中更新入群审核策略参数
        if (!iYunXinInterface.updateSessionJoinMode(request.getTid(), poJo.getOwnerId(), request.getJoinMode(), error)) {
            return false;
        }

        //再更新本地系统中的群主信息。
        IExecuteResult<Boolean> executeResult = sessionService.updateSessionJoinMode(operatorId, request.getTid(),
                request.getJoinMode(), principal);
        if (executeResult.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(executeResult.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public boolean transferSession(Long operatorId, TransferOwnerRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("群组(ID={0})不存在", "" + request.getTid()));
            return false;
        }

        if (!poJo.getOwnerId().equals(operatorId)) {
            error.append("当前用户不是群主");
            return false;
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        //先到云信平台中转让群主。
        if (!iYunXinInterface.transferSession(operatorId, request.getTid(), type, request.getNewOwnerId(), request.isLeave(), error)) {
            return false;
        }

        //再更新本地系统中的群主信息。
        IExecuteResult<Boolean> executeResult = sessionService.transferSession(operatorId, request.getTid(),
                request.getNewOwnerId(), request.isLeave(), principal);
        if (executeResult.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(executeResult.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public boolean addManager(Long operatorId, NewManagerRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()));
            return false;
        }

        if (request.getManagerIds().contains(poJo.getOwnerId())) {
            error.append("管理员ID列表中不能包含群主ID");
            return false;
        }

        if (!poJo.getOwnerId().equals(operatorId)) {
            error.append("当前用户不是群主");
            return false;
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        //先到云信平台中添加群组管理员。
        if (!iYunXinInterface.addManager(operatorId, request.getTid(), type, request.getManagerIds(), error)) {
            return false;
        }

        //再更新本地系统中的群主信息。
        IExecuteResult<Boolean> executeResult = sessionService.addManager(operatorId, request.getTid(), request.getManagerIds(), principal);
        if (executeResult.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(executeResult.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public boolean removeManager(Long operatorId, NewManagerRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()));
            return false;
        }

        if (!poJo.getOwnerId().equals(operatorId)) {
            error.append("当前用户不是群主");
            return false;
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        //先到云信平台中移除群组管理员。
        if (!iYunXinInterface.removeManager(operatorId, request.getTid(), type, request.getManagerIds(), error)) {
            return false;
        }

        //再更新本地系统中的群主信息。
        IExecuteResult<Boolean> executeResult = sessionService.removeManager(operatorId, request.getTid(), request.getManagerIds(), principal);
        if (executeResult.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(executeResult.getMsg());
            return false;
        }
        return true;
    }

    @Override
    public IExecuteResult<MemberInfo> getMemberDetailInSession(Long operatorId, Long tid) {
        ChatSessionPoJo poJo = sessionService.findById(tid);
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + tid), null);
        }

        ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(operatorId, tid);
        MemberInfo memberInfo = sessionService.getMemberInfoBy(operatorId, memberPoJo);
        return ExecuteResult.success(memberInfo);
    }

    @Override
    public IExecuteResult<QueryMembersResponse> slideQueryMemberInSession(Long operatorId, SlideQueryRequest request) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()), null);
        }

        List<ChatSessionMemberPoJo> memberPoJos = sessionService.slideQueryMemberInSession(poJo.getOwnerId(), request);

        List<MemberInfo> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(memberPoJos)) {
            list = convertToMemberInfos(operatorId, memberPoJos);
        }

        QueryMembersResponse response = new QueryMembersResponse(list);
        BeanUtils.copyProperties(request, response);
        return ExecuteResult.success(response);
    }

    @Override
    public IExecuteResult<QueryMembersResponse1> pageQueryMemberInSession(long currentUserId, long tid, int pageIndex, int pageSize) {
        ChatSessionPoJo poJo = sessionService.findById(tid);
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + tid), null);
        }

        List<ChatSessionMemberPoJo> memberPoJos = new ArrayList<>();
        long total = sessionService.pageQueryMemberInSession(tid, pageIndex, pageSize, memberPoJos);

        List<MemberInfo> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(memberPoJos)) {
            list = sessionService.getMemberInfoBy(currentUserId, memberPoJos);
        }
        QueryMembersResponse1 response = new QueryMembersResponse1(pageIndex, pageSize, total, list);
        return ExecuteResult.success(response);
    }

    @Override
    public IExecuteResult<Boolean> pullInBlackBill(Long currentUserId, SessionBlackBillRequest request) {
        if (Objects.equals(currentUserId, request.getUserId())) {
            return ExecuteResult.failure("目标用户不能是当前用户", null);
        }

        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()), null);
        }

        ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(currentUserId, request.getTid());
        if (memberPoJo == null) {
            return ExecuteResult.failure("当前用户不是该群组的成员", null);
        }

        if (memberPoJo.getRoleInSession() == 3) {
            return ExecuteResult.failure("当前用户没有黑名单管理权限", null);
        }

        if (request.getPullIn()) {
            memberPoJo = sessionService.getSessionMemberBy(request.getUserId(), request.getTid());
            if (memberPoJo != null) {
                if (memberPoJo.getRoleInSession() != 3) {
                    return ExecuteResult.failure("目标用户不能是群主或管理员", null);
                }
                StringBuilder error = new StringBuilder();
                //调用云信平台的踢出成员接口。
                iYunXinInterface.kickOutSession(currentUserId, request.getTid(), ChatSessionType.GROUP, List.of(request.getUserId()), error);
                //删除缓存和本地数据库中的成员记录。
                sessionService.removeMember(memberPoJo.getKey());
            }
        }

        //将用户加入或踢出群黑名单中。
        sessionService.pullInBlackBill(currentUserId, request);
        return ExecuteResult.success(true);
    }

    @Override
    public IExecuteResult<BlackBillResponse> listBlackBill(Long tid, int pageIndex, int pageSize) {
        ChatSessionPoJo poJo = sessionService.findById(tid);
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + tid), null);
        }

        String sql = MessageFormat.format("select count(*) from {0} where sessionId = ? ", BlackBillPoJo.CACHE_NAME);
        long total = IgniteQueryHelper.getCountBy(sql, new Object[]{tid}, sessionService.getBlackBillCache());

        sql = MessageFormat.format("select * from {0} where sessionId = ? order by createTime limit ?, ?", BlackBillPoJo.CACHE_NAME);
        List<BlackBillPoJo> blackBillPoJos = IgniteQueryHelper.findAllBy(sql, new Object[]{tid, pageIndex * pageSize, pageSize},
                BlackBillPoJo.class, sessionService.getBlackBillCache());
        List<SimpleUserInfo> simpleUserInfos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(blackBillPoJos)) {
            for (BlackBillPoJo blackBillPoJo : blackBillPoJos) {
                IMUserPoJo userPoJo = sessionService.getUserCache().get(blackBillPoJo.getUserId());
                SimpleUserInfo userInfo = new SimpleUserInfo();
                simpleUserInfos.add(userInfo);

                BeanUtils.copyProperties(userPoJo, userInfo);
                String avatar = "http://" + serviceProperties.getExternalManagerService() + userInfo.getAvatar();
                userInfo.setAvatar(avatar);
            }
        }
        BlackBillResponse response = new BlackBillResponse(tid, pageIndex, pageSize, (int) total, simpleUserInfos);
        return ExecuteResult.success(response);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        sessionService = applicationContext.getBean(ChatSessionService.class);
        iYunXinInterface = applicationContext.getBean(IYunXinInterface.class);
        serviceProperties = applicationContext.getBean(CurrentServiceProperties.class);
    }

    private List<MemberInfo> convertToMemberInfos(Long currentUserId, List<ChatSessionMemberPoJo> memberPoJos) {
        List<MemberInfo> list = new ArrayList<>();
        for (ChatSessionMemberPoJo memberPoJo : memberPoJos) {
            MemberInfo memberInfo = sessionService.getMemberInfoBy(currentUserId, memberPoJo);
            list.add(memberInfo);
        }
        return list;
    }

}
